package com.sunrise.xdoc.helper;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Repository;

import com.sunrise.xdoc.dao.IBaseDao;
import com.sunrise.xdoc.entity.AbstractIdEntity;

@Repository("daoHelper")
public class DaoHelper implements ApplicationContextAware, Serializable {
    private static final long serialVersionUID = 95537762458935875L;

    private Map<Class<?>, IBaseDao<?>> mapDAOs = new HashMap<>();

    private ApplicationContext applicationContext;

    @SuppressWarnings("unchecked")
    public <T extends AbstractIdEntity> IBaseDao<T> getDao(Class<T> entityClass) {
        IBaseDao<T> dao = (IBaseDao<T>) mapDAOs.get(entityClass);
        if (dao == null) {
            try {
                dao = (IBaseDao<T>) applicationContext.getBean(StringUtils.uncapitalize(entityClass.getSimpleName())
                        + "Dao");
            } catch (BeansException e) {
                // If the bean DAO has not defined yet, create a default DAO for
                // that entity.
                dao = (IBaseDao<T>) applicationContext.getBean("defaultBaseDao");
            }
        }
        dao.setEntityClass(entityClass);
        mapDAOs.put(entityClass, dao);
        return dao;
    }

    public <E extends IBaseDao<T>, T extends AbstractIdEntity> E getDao(Class<T> entityClass, Class<E> daoClass) {
        return daoClass.cast(getDao(entityClass));
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @Autowired
    private SessionFactory sessionFactory;

    public SessionFactory getSessionFactory() {
        return sessionFactory;
    }

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    public Session getSession() {
        return getSessionFactory().getCurrentSession();
    }
}
